#include "stdafx.h"
#include "LitMetaObject.h"

namespace Lit
{
	MetaObject::MetaObject( const String &name ) : Named(name){}
	MetaObject::MetaObject( const MetaObject& rk ){ mProps = rk.mProps; Named::operator=(rk);}
	MetaObject& MetaObject::operator=( const MetaObject& rk ){ mProps = rk.mProps; Named::operator=(rk); return *this; }
	MetaObject::~MetaObject(){}
		
	MetaGroup& MetaObject::getGroup( const String &name )
	{
		if( !hasGroup( name ) ) 
			throw ItemMissing( "Group "+name, "MetaObject "+mName, EXC_LOC );
		return mProps[name];
	}
	const MetaGroup& MetaObject::getGroup( const String &name ) const
	{
		if( !hasGroup( name ) ) 
			throw ItemMissing( "Group "+name, "MetaObject "+mName, EXC_LOC );
		return mProps.at(name);
	}

	void MetaObject::setGroup( const MetaGroup& d ){ mProps[d.getName()] = d;}
	void MetaObject::setProperty( const String &group, const String &key, const String &val ){	
		if( !hasGroup( group ) ) mProps[group] = MetaGroup( this, group);
		MetaGroup & g( mProps[group] );
		g.setProperty( key, val );
	}

	MetaGroup& MetaObject::operator[]( const String &name )
	{
		if( mProps.find(name) == mProps.end() )
			mProps[name] = MetaGroup(this, name);
		return mProps[name];
	}

	MetaObject::GroupMap::iterator MetaObject::find( const String &key ){ return mProps.find(key); }
	MetaObject::GroupMap::const_iterator MetaObject::find( const String &key ) const{ return mProps.find(key); }
		
	MetaObject::GroupMap::iterator MetaObject::begin(){ return mProps.begin(); }
	MetaObject::GroupMap::iterator MetaObject::end(){ return mProps.end(); }

	MetaObject::GroupMap::const_iterator MetaObject::begin() const{ return mProps.begin(); }
	MetaObject::GroupMap::const_iterator MetaObject::end() const{ return mProps.end(); }
	
	void MetaObject::merge( const MetaGroup& rk, bool replace_old ){
		if( hasGroup( rk.getName() ) ) mProps[rk.getName()].merge(rk);
		else setGroup( rk );
	}
	void MetaObject::merge( const MetaObject& rk, bool replace_old )
	{
		for( auto i=rk.begin(); i!=rk.end(); i++ ){
			const MetaGroup& g(i->second);
			merge( g, replace_old );
		}
	}

	bool MetaObject::hasGroup( const String &name ) const{ return find(name) != end(); }
		

	MetaGroupSerialiser::MetaGroupSerialiser():XmlSerialiser<MetaGroup>("MetaGroupSerialiser", 1.0f){}
	MetaGroupSerialiser::~MetaGroupSerialiser(){}

	void MetaGroupSerialiser::saveObject( TiXmlDocument * doc, const MetaGroup& in )
	{
		TiXmlElement * root = new TiXmlElement("MetaGroup");
		root->SetAttribute( "name", in.getName().data() );
		for( MetaGroup::Map::const_iterator i=in.begin(); i!=in.end(); i++ )
		{
			TiXmlElement * prop = new TiXmlElement("property");
			prop->SetAttribute("name", i->first.data());
			prop->LinkEndChild( new TiXmlText(i->second.getValue().data()) );
			root->LinkEndChild(prop);
		}
		doc->LinkEndChild(root);
	}
	void MetaGroupSerialiser::loadObject( TiXmlDocument * doc, const String &base_dir, MetaGroup& out )
	{
		TiXmlHandle hRoot(doc->FirstChildElement("MetaGroup"));
		TiXmlElement * project = hRoot.ToElement();
		if( project )
		{
			String name(project->Attribute("name"));
			out.setName(name);
			TiXmlElement * prop = project->FirstChildElement("property");
			for( prop; prop; prop = prop->NextSiblingElement() )
			{
				String key(prop->Attribute("name"));
				String val(prop->GetText());
				if( !key.empty() )
				{
					out.setProperty( key, val );
#ifndef NDEBUG
					OutputDebugString(("Found meta property "+out.getName()+"::"+key+"="+val+"\r\n").data() );
#endif
				}
			}
		}
	}
	
	void MetaGroupSerialiser::saveObject( TiXmlElement * doc, const MetaGroup& in ){
		TiXmlElement * root = new TiXmlElement("MetaGroup");
		root->SetAttribute( "name", in.getName().data() );
		for( MetaGroup::Map::const_iterator i=in.begin(); i!=in.end(); i++ )
		{
			TiXmlElement * prop = new TiXmlElement("property");
			prop->SetAttribute("name", i->first.data());
			prop->LinkEndChild( new TiXmlText(i->second.getValue().data()) );
			root->LinkEndChild(prop);
		}
		doc->LinkEndChild(root);
	}
	void MetaGroupSerialiser::loadObject( TiXmlElement * doc, const String &base_dir, MetaGroup& out ){
		TiXmlHandle hRoot(doc->FirstChildElement("MetaGroup"));
		TiXmlElement * project = hRoot.ToElement();
		if( project )
		{
			String name(project->Attribute("name"));
			out.setName(name);
			TiXmlElement * prop = project->FirstChildElement("property");
			for( prop; prop; prop = prop->NextSiblingElement() )
			{
				String key(prop->Attribute("name"));
				String val(prop->GetText());
				if( !key.empty() )
				{
					out.setProperty( key, val );
#ifndef NDEBUG
					OutputDebugString(("Found meta property "+out.getName()+"::"+key+"="+val+"\r\n").data() );
#endif
				}
			}
		}
	}

	MetaObjectSerialiser::MetaObjectSerialiser(const String &override_name) : XmlSerialiser( override_name, 1.0f ){}
	MetaObjectSerialiser::MetaObjectSerialiser():XmlSerialiser<MetaObject>("MetaObjectSerialiser", 1.0f){}
	MetaObjectSerialiser::~MetaObjectSerialiser(){}
	
	void MetaObjectSerialiser::saveObject( TiXmlDocument * doc, const MetaObject& in )
	{
		TiXmlElement * root = new TiXmlElement("MetaObject");
		root->SetAttribute( "name", in.getName().data() );
		for( MetaObject::GroupMap::const_iterator i=in.begin(); i!=in.end(); i++ )
		{
			MetaGroupSerialiser ser;
			ser.saveObject( root, i->second );
		}
		doc->LinkEndChild(root);
	}
	void MetaObjectSerialiser::loadObject( TiXmlDocument * doc, const String &base_dir, MetaObject& out )
	{
		TiXmlHandle hRoot(doc->FirstChildElement("MetaObject"));
		TiXmlElement * project = hRoot.ToElement();
		if( project )
		{
			String name(project->Attribute("name"));
			out.setName(name);
			TiXmlElement * prop = project->FirstChildElement("MetaGroup");
			for( prop; prop; prop = prop->NextSiblingElement() )
			{
				MetaGroup g;
				MetaGroupSerialiser ser;
				ser.loadObject( project, base_dir, g );
				out.setGroup( g );
			}
		}
	}
};